Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | export const dynamic = "force-dynamic"; /** * Close Support Ticket API * POST /api/support/tickets/[id]/close - Close a ticket (customer) */ import { NextRequest, NextResponse } from "next/server"; import { Session } from "next-auth"; import { prisma } from "@/lib/prisma"; import { recordStatusChange } from "@/lib/support/ticket-utils"; import { TicketStatus } from "@/types/support"; import { logger } from "@/lib/logging"; import { withErrorHandling, withAuth, successResponse, ApiError } from "@/lib/api"; import { RouteContext } from "@/lib/api/middleware"; /** * POST /api/support/tickets/[id]/close * Close a ticket (customer can close their own tickets) */ async function handlePost( _request: NextRequest, context: RouteContext | undefined, session: Session ): Promise<NextResponse> { if (!context?.params) { throw ApiError.invalidId("ticket"); } const { id } = await context.params; const userId = Number(session.user.id); // Verify ticket exists and belongs to user const ticket = await prisma.supportTicket.findUnique({ where: { id }, select: { id: true, userId: true, status: true, ticketNumber: true }}); if (!ticket) { throw ApiError.notFound("Ticket", id); } if (ticket.userId !== userId) { throw ApiError.forbidden("Access denied"); } // Check if ticket can be closed const closableStatuses = [ TicketStatus.OPEN, TicketStatus.IN_PROGRESS, TicketStatus.AWAITING_CUSTOMER, TicketStatus.AWAITING_AGENT, TicketStatus.RESOLVED, ]; if (!closableStatuses.includes(ticket.status as TicketStatus)) { throw ApiError.validation("This ticket cannot be closed"); } const oldStatus = ticket.status as TicketStatus; // Close the ticket const updatedTicket = await prisma.supportTicket.update({ where: { id }, data: { status: TicketStatus.CLOSED, closedAt: new Date()}}); // Record status change await recordStatusChange(id, oldStatus, TicketStatus.CLOSED, userId); // Add system message await prisma.supportMessage.create({ data: { ticketId: id, senderType: "SYSTEM", senderName: "System", content: "Ticket closed by customer.", isInternal: false}}); logger.info("Ticket closed by customer", { category: "API", ticketId: id, ticketNumber: ticket.ticketNumber, userId}); return successResponse({ ...updatedTicket, message: "Ticket closed successfully"}); } export const POST = withErrorHandling(withAuth(handlePost)); |